package app.engine.component;

import app.engine.component.Engine;
import app.engine.component.MoveGenerator;
import app.engine.entitys.EvaluationTable;
import app.engine.entitys.Move;
import app.engine.enums.MoveScoreAttackType;
import app.engine.enums.MoveScoreDefenseType;
import app.game.ChessBoard;
import app.game.ChessPoint;
import app.game.enums.Chess;
import app.game.enums.Direction;
import app.ui.Config;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Description 搜索引擎抽象类
 * @Date 2022/4/18 20:54
 * @Created by LYP
 */
public abstract class AbstractSearchEngine implements MoveGenerator, Engine, Config {

    protected EvaluationTable evaluationTable = new EvaluationTable();

    protected TranspositionTable transpositionTable = new TranspositionTable();

    /**
     * 走法生成
     * @param chessBoard
     * @param nowChess
     * @return
     */
    public List<Move> getMoves(Chess[][] chessBoard, Chess nowChess) {
        List<Move> moves = new ArrayList<>();
        for (int i = 0; i < BOARD_LINE; i++) {
            for (int j = 0; j < BOARD_LINE; j++) {
                if (chessBoard[i][j] == Chess.EMPTY) {
                    Move move = new Move(i, j, 0);
                    chessBoard[move.getX()][move.getY()] = nowChess;
                    int score = getMoveScore(new ChessPoint(i, j), chessBoard, nowChess);
                    chessBoard[move.getX()][move.getY()] = Chess.EMPTY;
                    move.setScore(score);
                    // 去掉0分
                    if (score > 0){
                        //System.out.println("局面生成走法["+i+", "+j+"]，评分为"+ score);
                        moves.add(move);
                    }

                }

            }
        }
        return moves;
    }

    /**
     * 走法评分
     * @param nowPoint
     * @param chessBoard
     * @param nowChess
     * @return
     */
    private int getMoveScore(ChessPoint nowPoint, Chess[][] chessBoard, Chess nowChess) {
        int totalScore = 0;
        Direction[] directions = Direction.values();
        for (Direction direction: directions) {
            // 计算位置得分，优先考虑靠近棋子的点
            int positionScore = 0;
            ChessPoint point = nowPoint.getNext(direction, 1);
            if (point.isOnTable() && chessBoard[point.getX()][point.getY()] != Chess.EMPTY) {
                positionScore++;
            }
            point = nowPoint.getNext(direction, -1);
            if (point.isOnTable() && chessBoard[point.getX()][point.getY()] != Chess.EMPTY) {
                positionScore++;
            }
            if (positionScore > 0) {
                //System.out.println(direction.getName() + "的位置评分为" + positionScore);
            }
            totalScore += positionScore;
            // 先计算进攻分
            point = nowPoint.getNext(direction, 1);
            int chessCount = 0;
            int endCount = 0;
            while (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess){
                point = point.getNext(direction, 1);
            }
            if (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess.getReverse()){
                endCount++;
            }
            point = point.getNext(direction, -1);
            while (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess){
                chessCount++;
                point = point.getNext(direction, -1);
            }
            if (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess.getReverse()){
                endCount++;
            }
            int aScore = MoveScoreAttackType.matchScore(chessCount, endCount);
            if (aScore > 0) {
                //System.out.println(direction.getName() + "的进攻评分为" + aScore);
            }
            totalScore += aScore;
            //计算防守分
            int defChessCount = 0;
            int defEndCount = 0;
            int defType = 0;
            point = nowPoint.getNext(direction, 1);
            if (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess.getReverse()) {
                defType++;
            }
            while (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess.getReverse()){
                defChessCount++;
                point = point.getNext(direction, 1);
            }
            if (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess) {
                defEndCount++;
            }
            point = nowPoint.getNext(direction, -1);
            if (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess.getReverse()) {
                defType++;
            }
            while (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess.getReverse()){
                defChessCount++;
                point = point.getNext(direction, -1);
            }
            if (point.isOnTable() && chessBoard[point.getX()][point.getY()] == nowChess) {
                defEndCount++;
            }
            int dScore = MoveScoreDefenseType.matchScore(defChessCount, defEndCount, defType);
            if (dScore > 0) {
                //System.out.println(direction.getName() + "的防守评分为" + dScore);
            }
            totalScore += dScore;
        }
        return totalScore;
    }

    /**
     * 局面估值函数
     * 1、五连 活四 999999分
     * 2、1个冲四  10分   2个以上冲四  999999分
     * 3、1个活三  20分   2个以上活三  999999分
     * 4、每个活二  2分   每个冲2  1分
     * @param chessBoard
     * @return
     */
    protected int getValuation(Chess[][] chessBoard, Chess nowChess) {
        evaluationTable.init();
        int totalScore = 0;
        // 记录每种模式的分数
        //List<Integer> scoreList = new ArrayList<>();
        // 遍历整个棋盘
        for (int i = 0; i < BOARD_LINE; i++) {
            for (int j = 0; j < BOARD_LINE; j++) {
                ChessPoint thisPoint = new ChessPoint(i, j);
                // 遍历四个方向
                for (Direction direction: Direction.values()) {
                    Chess[] checkArray = new Chess[EvaluationTable.MAX_MODE_LINE];
                    ChessPoint now = new ChessPoint(i, j);
                    // 从当前位置开始，按照方向收集从当前点开始的MIN_MODE_LINE到MAX_MODE_LINE个棋子，进入模式匹配
                    for (int k = 0; k < EvaluationTable.MAX_MODE_LINE; k++) {
                        if (!now.isOnTable()) {
                            break;
                        }
                        // 放入当前棋子
                        checkArray[k] = chessBoard[now.getX()][now.getY()];
                        // 如果大于模式匹配的最小个数，就进入匹配，并记录分数
                        if (k >= EvaluationTable.MIN_MODE_LINE - 1) {
                            totalScore += evaluationTable.checkChessList(checkArray, k, nowChess);
                        }
                        // 移动到下一个位置
                        now.next(direction, 1);
                    }
                }

            }
        }
        // 遍历分数记录，求总和
        //for (int score: scoreList) {
        //    totalScore += score;
        //}
        return totalScore;
    }

    public void printChessBoard(Chess[][] chessBoard) {
        for (int i = 0; i < BOARD_LINE; i++) {
            for (int j = 0; j < BOARD_LINE; j++) {
                System.out.print(chessBoard[i][j].getItem());
            }
            System.out.println();
        }
    }



    abstract public ChessPoint search(Chess[][] chessBoard, Chess comChess, int step, List<ChessPoint> stepHistory);
}
